home *** CD-ROM | disk | FTP | other *** search
- /********************************************************************
- * $Author: drich $
- * $Revision: 1.1 $
- * $Date: 1995/10/03 04:08:31 $
- * $Source: /proj/freeware1.0/gopher1.12/src/gopherd/RCS/gopherd.c,v $
- * $State: Exp $
- *
- * Paul Lindner, University of Minnesota CIS.
- *
- * Copyright 1991, 1992 by the Regents of the University of Minnesota
- * see the file "Copyright" in the distribution for conditions of use.
- *********************************************************************
- * MODULE: gopherd.c
- * Routines to implement the gopher server.
- *********************************************************************
- * Revision History:
- * $Log: gopherd.c,v $
- * Revision 1.1 1995/10/03 04:08:31 drich
- * gopher 1.2 check-in
- *
- * Revision 1.2.1.6 1993/01/09 02:37:29 lindner
- * Added ftp gateway logging
- * Changed gethostbyaddr() to work on UNICOS
- *
- * Revision 1.2.1.5 1993/01/05 21:32:25 lindner
- * Fixed printfile() so that it deals with files with a period on a line
- * all by itself correctly. Also removed one writestring() call.
- *
- * Revision 1.2.1.4 1993/01/05 21:10:38 lindner
- * Removed setuid() call that broke when using -u and chroot()
- *
- * Revision 1.2.1.3 1992/12/22 21:55:30 lindner
- * fixed typo, int was meant to be double.. Grrrr
- *
- * Revision 1.2.1.2 1992/12/22 21:48:15 lindner
- * Added extern maxload, fixes bug with previous version...
- *
- * Revision 1.2.1.1 1992/12/21 20:51:52 lindner
- * Moved loadrestrict stuff to kernutils.c, also the server
- * can now restrict for load average from standalone mode.
- *
- * Revision 1.2 1992/12/13 06:13:59 lindner
- * Added code to do readline timeouts <mtm>
- *
- * Revision 1.1 1992/12/10 23:13:27 lindner
- * gopher 1.1 release
- *
- *
- *********************************************************************/
-
-
- /* Originally derived from an
- * Example of server using TCP protocol
- * pp 284-5 Stevens UNIX Network Programming
- */
-
-
- #include "gopherd.h"
- void LOGGopher();
-
- static int uid = -2;
-
- extern char *getdesc();
- extern double maxload;
- void Process_Side();
-
-
-
- /* This function is called on a read timeout from the network */
-
- #include <setjmp.h>
- jmp_buf env;
-
- SIGRETTYPE read_timeout()
- {
- longjmp(env,1);
- }
-
-
- /*
- * This routine finds out the hostname of the server machine.
- * It uses a couple of methods to find the fully qualified
- * Domain name
- */
-
- char *
- GetDNSname(backupdomain)
- char *backupdomain;
- {
- static char DNSname[MAXHOSTNAMELEN];
- struct hostent *hp;
- char *cp;
-
- cp = GDCgetHostname(Config);
- if (*cp != '\0')
- return(cp);
-
- DNSname[0] = '\0';
- /* Work out our fully-qualified name, for later use */
-
- if (gethostname(DNSname, MAXHOSTNAMELEN) != 0) {
- fprintf(stderr, "Cannot determine the name of this host\n");
- exit(-1);
- }
-
- /* Now, use gethostbyname to (hopefully) do a nameserver lookup */
- hp = gethostbyname( DNSname);
-
- /*
- ** If we got something, and the name is longer than hostname, then
- ** assume that it must the the fully-qualified hostname
- */
- if ( hp!=NULL && strlen(hp->h_name) > strlen(DNSname) )
- strncpy( DNSname, hp->h_name, MAXHOSTNAMELEN );
- else
- strcat(DNSname, backupdomain);
-
- return(DNSname);
- }
-
-
- /*
- * Tries to figure out what the currently connected port is.
- *
- * If it's a socket then it will return the port of the socket,
- * if it isn't a socket then it returns -1.
- */
-
- int GetPort(fd)
- int fd;
- {
- struct sockaddr_in serv_addr;
-
- int length = sizeof(serv_addr);
-
- /** Try to figure out the port we're running on. **/
-
- if (getsockname(fd, (struct sockaddr *) &serv_addr,&length) == 0)
- return(ntohs(serv_addr.sin_port));
- else
- return(-1);
-
- }
-
-
- /*
- * This function returns a socket file descriptor bound to the given port
- */
-
- int
- bind_to_port(port)
- int port;
- {
- struct sockaddr_in serv_addr;
- struct linger linger;
- int reuseaddr = 1;
- int sockfd;
-
-
- if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- err_dump("server: can't open stream socket");
-
- /** Bind our local address so that the client can send to us **/
-
- bzero((char *) &serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- serv_addr.sin_port = htons(port);
-
- if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <0)
- err_dump("server: can't bind local address");
- linger.l_onoff = linger.l_linger = 0;
- if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *)&linger,
- sizeof (linger)) < 0)
- err_dump("server: can't turn off linger sockopt");
-
- if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr,
- sizeof(reuseaddr)) < 0)
- err_dump("server: can't set REUSEADDR!");
-
- return(sockfd);
- }
-
- void
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int childpid;
- int sockfd, newsockfd;
- int clilen;
- struct sockaddr_in cli_addr;
- boolean OptionsRead = FALSE;
-
-
- /*** for getopt processing ***/
- int c;
- extern char *optarg;
- extern int optind;
- int errflag =0;
-
-
- pname = argv[0];
- strcpy(Data_Dir, DATA_DIRECTORY);
- err_init(); /* openlog() early - before we chroot() of course */
-
- /*** Check argv[0], see if we're running as gopherls, etc. ***/
-
- RunServer = RunLS = RunIndex = FALSE;
-
- if (strstr(argv[0], "gopherls") != NULL) {
- RunLS = TRUE;
- } else if (strstr(argv[0], "gindexd") != NULL) {
- RunIndex = TRUE;
- dochroot = FALSE;
- } else
- RunServer = TRUE; /** Run the server by default **/
-
- Config = GDCnew(); /** Set up the general configuration **/
-
- while ((c = getopt(argc, argv, "mCDIcL:l:o:u:U:")) != -1)
- switch (c) {
- case 'D':
- DEBUG = TRUE;
- break;
-
- case 'I':
- RunFromInetd = TRUE;
- break;
-
- case 'C':
- Caching = FALSE;
- break;
-
- case 'm':
- if (RunIndex)
- MacIndex = TRUE;
- break;
-
- case 'c':
- dochroot = FALSE;
- if (!RunFromInetd) {
- printf("Not using chroot() - be careful\n");
- if ( getuid() == 0 || geteuid() == 0 )
- printf("You should run without root perms\n");
- }
- break;
-
- case 'L': /** Load average at which to restrict usage **/
- maxload = atof(optarg);
- break;
-
- case 'l': /** logfile name **/
- if (*optarg == '/')
- GDCsetLogfile(Config, optarg);
- else {
- char tmpstr[256];
-
- getwd(tmpstr);
- strcat(tmpstr, "/");
- strcat(tmpstr, optarg);
-
- GDCsetLogfile(Config, tmpstr);
- }
- break;
-
- case 'o': /** option file **/
- if (*optarg == '/')
- GDCfromFile(Config, optarg);
- else {
- char tmpstr[256];
- getwd(tmpstr);
- strcat(tmpstr, "/");
- strcat(tmpstr, optarg);
- GDCfromFile(Config, tmpstr);
- }
- OptionsRead = TRUE;
- break;
-
- case 'u':
- {
- struct passwd *pw = getpwnam( optarg );
- if ( !pw ) {
- fprintf(stderr,
- "Could not find user '%s' in passwd file\n",
- optarg);
- errflag++;
- } else {
- uid = pw->pw_uid;
- if (!RunFromInetd) {
- printf("Running as user '%s' (%d)\n",
- optarg, uid);
- }
- }
- }
- break;
-
- case 'U': /* set uid to use */
- uid = atoi( optarg );
- if (!RunFromInetd) {
- printf("Running using uid %d\n", uid);
- }
- break;
- case '?':
- case 'h':
- errflag++;
- break;
- }
-
-
- if (errflag) {
- fprintf(stderr, "Usage: %s [-CDIc] [-u userid] [-U uid] [-s securityfile] [-l logfile] <datadirectory> <port>\n", argv[0]);
- fprintf(stderr, " -C turns caching off\n");
- fprintf(stderr, " -D enables copious debugging info\n");
- fprintf(stderr, " -I enable \"inetd\" mode\n");
- fprintf(stderr, " -c disable chroot(), use secure open routines instead\n");
- fprintf(stderr, " -u specifies the username for use with -c\n");
- fprintf(stderr, " -U specifies the UID for use with -c\n");
- fprintf(stderr, " -o override the default options file '%s'\n", CONF_FILE);
- fprintf(stderr, " -l specifies the name of a logfile\n");
-
- exit(-1);
- }
-
- if (uid == -2)
- uid = getuid(); /** Run as current user... **/
-
- if ( uid == 0 && !RunFromInetd )
- printf("Warning! You really shouldn't run the server as root!...\n");
-
-
- if (optind < argc) {
- strcpy(Data_Dir, argv[optind]);
- optind++;
- } else if (RunLS)
- strcpy(Data_Dir, "/");
-
- if (optind < argc) {
- GopherPort = atoi(argv[optind]);
- optind++;
- }
-
- /** Read the options in, if not overridden **/
- if (OptionsRead == FALSE)
- GDCfromFile(Config, CONF_FILE);
-
-
- if (RunLS) {
- Zehostname =GetDNSname(DOMAIN_NAME);
- Caching = FALSE;
-
- fflush(stdout);
- uchdir(Data_Dir);
-
- listdir(fileno(stdout), "/");
- exit(0);
- }
-
- if (!RunFromInetd) {
- printf("Gopher Server, Copyright 1991,92 the Regents of the University of Minnesota\n");
- printf("See the file 'Copyright' for conditions of use\n");
- printf("Data directory is %s\n", Data_Dir);
- printf("Port is %d\n", GopherPort);
- }
-
- if (*GDCgetLogfile(Config) != '\0' && !RunFromInetd)
- printf("Logging to File %s\n", GDCgetLogfile(Config));
-
- /*
- * Would like to setuid() here, but have to wait until after the
- * bind() in case we're going to be running on a privileged port.
- */
-
- if (uchdir(Data_Dir)) {
- if (!RunIndex) {
- fprintf(stderr, "Cannot change to data directory!! %s \n",Data_Dir);
- exit(-1);
- }
- }
-
- if (dochroot && getuid() != 0) {
- fprintf(stderr, "Gopherd uses the privileged call chroot(). Please become root.\n");
- exit(-1);
- }
-
- fflush(stderr);
- fflush(stdout);
-
- if (DEBUG == FALSE && RunFromInetd==FALSE)
- daemon_start(0);
-
-
- /*** Hmmm, does this look familiar? :-) ***/
-
-
- err_init(); /* does this look familiar too?? :-) */
-
- /** Ask the system what host we're running on **/
-
- Zehostname = GetDNSname(DOMAIN_NAME);
-
-
- if (RunFromInetd) {
- /** Ask the system which port we're running on **/
- int newport=0;
- if ((newport =GetPort(0)) !=0)
- GopherPort=newport;
-
- /*** Do the stuff for inetd ***/
-
- while(do_command(0)!=0); /* process the request */
- exit(0);
- }
-
- /** Open a TCP socket (an internet stream socket **/
- sockfd = bind_to_port(GopherPort);
-
- /* have to setuid() here, in case we're using a privileged port */
- /* if ( setuid(uid) != 0 )
- err_sys("Cannot setuid(%d): ",uid);*/
-
- listen(sockfd, 5);
-
- for ( ; ; ) {
- /*
- * Wait for a connection from a client process.
- * This is an example of a concurrent server.
- */
-
- clilen = sizeof(cli_addr);
- newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr,
- &clilen);
-
- if (newsockfd < 0)
- err_dump("server: accept error");
-
- if ( (childpid = fork()) < 0)
- err_dump("server: fork error");
-
- else if (childpid == 0) { /* Child process */
- close(sockfd); /* close original socket */
-
- while(do_command(newsockfd)!=0); /* process the request */
- exit(0);
- }
- /** clean up any zombie children **/
- sig_child();
-
- close(newsockfd); /* parent process */
- }
- }
-
-
- /*
- *
- * Code stolen from nntp.....
- *
- * inet_netnames -- return the network, subnet, and host names of
- * our peer process for the Internet domain.
- *
- * Parameters: "sock" is our socket
- * "host_name"
- * is filled in by this routine with the
- * corresponding ASCII names of our peer.
- *
- * if there doesn't exist a hostname in DNS etal,
- * the IP# will be inserted for the host_name
- *
- * "ipnum" is filled in with the ascii IP#
- * Returns: Nothing.
- * Side effects: None.
- */
-
- void
- inet_netnames(sockfd, host_name, ipnum)
- int sockfd;
- char *host_name;
- char *ipnum;
- {
- struct sockaddr_in sa;
- int length;
- u_long net_addr;
- struct hostent *hp;
-
- length = sizeof(sa);
- getpeername(sockfd, &sa, &length);
- strcpy(ipnum, inet_ntoa(sa.sin_addr));
- strcpy(host_name, inet_ntoa(sa.sin_addr));
-
- hp = gethostbyaddr((char *) &sa.sin_addr,
- sizeof (sa.sin_addr.s_addr), AF_INET);
-
- if (hp != NULL)
- (void) strcpy(host_name, hp->h_name);
-
- }
-
-
-
- /*
- * This finds the current peer and the time and jams it into the
- * logfile (if any) and adds the message at the end
- */
-
- void
- LOGGopher(sockfd, message)
- int sockfd;
- char *message;
- {
- static char host_name[256];
- static char ipnum[256];
- time_t Now;
- char *cp;
- /* cp + ' ' + host_name + ' : ' + MAXLINE + '\n' + '\0' */
- char buf[286+MAXLINE];
- struct flock lock;
-
-
- host_name[0] = '\0';
-
- if (LOGFileDesc != -1) {
-
- if (sockfd > -1) {
- inet_netnames(sockfd,host_name, ipnum);
- }
-
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0L;
- lock.l_len = 0L;
- fcntl(LOGFileDesc, F_SETLKW, &lock);
-
- time(&Now); /* Include this in the lock to make sure */
- cp = ctime(&Now); /* log entries are chronological */
- ZapCRLF(cp);
-
- /* someone else may have written to the file since we opened it */
- lseek(LOGFileDesc, 0L, SEEK_END);
-
- sprintf(buf, "%s %d %s : %s\n", cp, getpid(), host_name, message);
- write(LOGFileDesc, buf, strlen(buf));
-
- /* unlock the file */
- lock.l_type = F_UNLCK;
- fcntl(LOGFileDesc, F_SETLKW, &lock);
-
- if (DEBUG)
- printf("%s %d %s : %s\n", cp, getpid(), host_name, message);
-
- }
- }
-
- void
- process_mailfile(sockfd, Mailfname)
- int sockfd;
- char *Mailfname;
- {
- FILE *Mailfile;
- char Zeline[MAXLINE];
- char outputline[MAXLINE];
- char Title[MAXLINE];
- long Startbyte=0, Endbyte=0, Bytecount=0;
- boolean flagged = 0;
-
- Mailfile = rfopen(Mailfname, "r");
-
- if (Mailfile == NULL) {
- Abortoutput(sockfd, "Cannot access file");
- return;
- }
-
- while (fgets(Zeline, MAXLINE, Mailfile) != NULL) {
- if (strncmp(Zeline, "Subject: ", 9)==0 && (!flagged)) {
- flagged =1;
- strcpy(Title, Zeline + 9);
- ZapCRLF(Title);
- if (DEBUG)
- fprintf(stderr, "Found title %s", Title);
- }
-
- if (is_mail_from_line(Zeline)==0) {
- Endbyte = Bytecount;
- flagged =0;
-
- if (Endbyte != 0) {
- sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n",
- Title, Startbyte, Bytecount, Mailfname,
- Zehostname, GopherPort);
- if (writestring(sockfd, outputline) < 0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
- Startbyte=Bytecount;
- *Title = '\0';
- }
- }
-
- Bytecount += strlen(Zeline);
- }
-
- if (*Title != '\0') {
- sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n",
- Title, Startbyte, Bytecount, Mailfname,
- Zehostname, GopherPort);
- if (writestring(sockfd, outputline)<0)
- LOGGopher(sockfd, "Client went away"),exit(-1);
- }
-
-
- if (writestring(sockfd, ".\r\n")<0)
- LOGGopher(sockfd, "Client went away"),exit(-1);
- }
-
-
-
- boolean
- Can_Read(sockfd)
- int sockfd;
- {
- int length;
- char host_name[256];
- char ip[256];
- char *cp;
-
- inet_netnames(sockfd, host_name, ip);
-
- return(GDCCanRead(Config, host_name, ip));
- }
-
- boolean
- Can_Browse(sockfd)
- int sockfd;
- {
- int length;
- char host_name[256];
- char ip[256];
- char *cp;
-
- inet_netnames(sockfd, host_name, ip);
-
- return(GDCCanBrowse(Config, host_name, ip));
- }
-
- boolean
- Can_Search(sockfd)
- int sockfd;
- {
- int length;
- char host_name[256];
- char ip[256];
- char *cp;
-
- inet_netnames(sockfd, host_name, ip);
-
- return(GDCCanSearch(Config, host_name, ip));
- }
-
-
- int
- do_command(sockfd)
- int sockfd;
- {
- char inputline[MAXLINE];
- int length; /* Length of the command line */
- char logline[MAXLINE];
- char *selstr;
-
- /*** Reopen the log file ***/
-
- if (*GDCgetLogfile(Config) != '\0') {
- LOGFileDesc = uopen(GDCgetLogfile(Config), O_WRONLY | O_APPEND |O_CREAT, 0644);
-
- if (LOGFileDesc == -1) {
- printf("Can't open the logfile: %s\n", GDCgetLogfile(Config));
- exit(-1);
- }
- }
-
- if(LoadTooHigh()) {
- LOGGopher(sockfd, "System Load Too High.");
- Abortoutput(sockfd, "System is too busy right now. Please try again later.");
- exit(-1);
- }
-
- /*** Make sure we do a tzset before doing a chroot() ***/
- tzset();
-
- /** Change our root directory **/
-
- if ( dochroot ) {
- if (chroot(Data_Dir)) {
- Abortoutput(sockfd, "Data_Dir dissappeared!");
- exit(-1);
- }
- uchdir("/"); /* needed after chroot */
- }
-
- if (setuid(uid)) {
- LOGGopher(sockfd, "Can't set UID!");
- Abortoutput(sockfd, "Can't set UID!");
- exit(-1);
- }
-
-
- (void) signal(SIGALRM,read_timeout);
- (void) alarm(READTIMEOUT);
-
- if(setjmp(env)) {
- LOGGopher(sockfd,"readline: Timed out!");
- Abortoutput(sockfd,"readline: Timed out!");
- exit(-1);
- }
-
- length = readline(sockfd, inputline, MAXLINE); /** Get the line **/
-
- /** Disable the alarm signal **/
- (void) alarm(0);
- (void) signal(SIGALRM,SIG_IGN);
-
-
- if (length <= 0) {
- close(sockfd);
- err_quit("getcommand: readline error");
- }
-
- ZapCRLF(inputline);
-
-
- /*
- * Decide if we're an HTML server or not...
- */
-
- if (strncmp(inputline, "GET /", 5) == 0) {
-
- UsingHTML = TRUE;
- selstr = inputline+5;
-
- /** Convert the hex things back to text... ***/
- Fromhexstr(selstr, selstr);
-
- } else
- selstr = inputline;
-
- if (RunIndex) {
- /*** Run like the old gindexd thing. ***/
-
- char tempstr[512];
-
- uchdir("/");
-
- strcpy(tempstr, Data_Dir);
- strcat(tempstr, "\t");
- if (*selstr == '\t')
- strcat(tempstr, selstr+1);
- else
- strcat(tempstr, selstr);
-
- strcpy(Data_Dir, "/");
-
- if (DEBUG)
- writestring(sockfd, tempstr);
-
-
- Do_IndexTrans(sockfd, tempstr);
- return(0);
- }
-
- /*** With the funky new capability system we can just check the
- first letter, end decide what the object refers to. ***/
-
- switch (*selstr) {
- case '\0':
- case '\t':
-
- /*** The null capability, so it's not a file, probably wants
- to talk to a directory server ***/
-
- /*** we'll just do a "list" of the root directory, with no user
- capability. ***/
-
- listdir(sockfd, "/");
- LOGGopher(sockfd, "Root Connection");
- break;
-
- case 'h':
- /*** A raw html file ***/
- /*** Turn off html'ing and just dump the file ***/
- UsingHTML = FALSE;
-
- case '0':
- /*** It's a generic file capability ***/
- printfile(sockfd, selstr+1, 0, -1);
-
- /*** Log it ***/
- strcpy(logline, "retrieved file ");
- strcat(logline, selstr+1);
- LOGGopher(sockfd, logline);
- break;
-
- case '1':
- /*** It's a directory capability ***/
- listdir(sockfd, selstr+1);
-
- /** Log it **/
- strcpy(logline, "retrieved directory ");
- strcat(logline, selstr+1);
- LOGGopher(sockfd, logline);
-
- break;
-
- case '7':
- /*** It's an index capability ***/
- if (Can_Search(sockfd) == FALSE) {
- char tmpstr[256];
-
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
-
- sprintf(tmpstr, "Denied access for %s", selstr+1);
- LOGGopher(sockfd, tmpstr);
- break;
- }
-
- Do_IndexTrans(sockfd, selstr+1);
-
- break;
-
- case 'I':
- case '9':
- /*** It's a binary thingie... ***/
- /*** Okay, it's not a sound, but what the heck.... ***/
- echosound(sockfd, selstr+1);
-
- /* Log it */
- strcpy(logline, "retrieved binary ");
- strcat(logline, selstr+1);
- LOGGopher(sockfd, logline);
- break;
-
- case 's':
- /*** It's a sound capability ***/
- echosound(sockfd, selstr+1);
-
- /* Log it */
- strcpy(logline, "retrieved sound ");
- strcat(logline, selstr+1);
- LOGGopher(sockfd, logline);
- break;
-
- case 'm':
- /*** This is an internal identifier ***/
- /*** The m paired with an Objtype of 1 makes a mail spool file
- into a directory.
- ***/
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", selstr+1);
- LOGGopher(sockfd, tmpstr);
- break;
- }
-
- process_mailfile(sockfd, selstr + 1);
-
- /** Log it **/
- strcpy(logline, "retrieved maildir ");
- strcat(logline, selstr+1);
- LOGGopher(sockfd, logline);
-
- break;
-
- case 'R':
- /*** This is an internal identifier ***/
- /*** The R defines a range ****/
- /*** The format is R<startbyte>-<endbyte>-<filename> **/
- {
- int startbyte, endbyte;
- char *cp, *oldcp;
-
- cp = strchr(selstr+1, '-');
-
- if (cp == NULL) {
- Abortoutput(sockfd, "Range specifier error");
- break;
- }
-
- *cp = '\0';
- startbyte = atoi(selstr+1);
- oldcp = cp+1;
-
- cp = strchr(oldcp, '-');
-
- if (cp == NULL) {
- Abortoutput(sockfd, "Range specifier error");
- exit(-1);
- }
-
- *cp = '\0';
- endbyte = atoi(oldcp);
- oldcp = cp + 1;
- if (DEBUG)
- fprintf(stderr, "Start: %d, End: %d File: %s\n", startbyte, endbyte, oldcp);
-
- writestring(sockfd, "This section is from the document '");
- writestring(sockfd, oldcp);
- writestring(sockfd, "'.\r\n\r\n");
- printfile(sockfd, oldcp, startbyte, endbyte);
-
- /*** Log it ***/
- sprintf(logline, "retrieved range %d - %d of file %s", startbyte, endbyte, oldcp);
- LOGGopher(sockfd, logline);
- break;
- }
-
- case 'f':
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", selstr);
- LOGGopher(sockfd, tmpstr);
- break;
- }
-
- if (strncmp(selstr, "ftp:",4)==0){
- sprintf(logline, "retrieved %s", selstr);
- LOGGopher(sockfd, logline);
-
- SendFtpQuery(sockfd, selstr+4);
- TranslateResults(sockfd);
- break;
- }
- break;
-
- case 'e':
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", selstr);
- LOGGopher(sockfd, tmpstr);
- break;
- }
-
- if (strncmp(selstr, "exec:", 5)==0) {
- /* args are between colons */
- char *args, *command;
-
- command = strrchr(selstr + 5, ':');
- if (command == NULL)
- break;
-
- if (*(selstr+5) == ':' && *(selstr+6) == ':')
- args = NULL;
- else
- args = selstr+5;
-
- *command = '\0';
- command++;
-
- EXECargs = args;
-
- printfile(sockfd, command, 0, -1);
- }
- break;
-
- case 'w':
- {
- if (strncmp(selstr, "waissrc:", 8) == 0) {
- if (Can_Search(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", selstr);
- LOGGopher(sockfd, tmpstr);
- break;
- }
-
- SearchRemoteWAIS(sockfd, selstr+8);
- break;
- }
- else if (strncmp(selstr, "waisdocid:", 10) == 0) {
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", selstr);
- LOGGopher(sockfd, tmpstr);
- break;
- }
- Fetchdocid(sockfd, selstr+10);
- break;
- }
- }
-
-
- default:
- /*** Hmmm, must be an old link... Let's see if it exists ***/
-
- switch (isadir(selstr)) {
- case -1:
- /* no such file */
- sprintf(logline, "'%s' does not exist", selstr);
- LOGGopher(sockfd, logline);
- Abortoutput(sockfd, logline);
- break;
-
- case 0:
- /* it's a file */
- printfile(sockfd, selstr, 0, -1);
-
- /* Log it... */
- strcpy(logline, "retrieved file ");
- strcat(logline, selstr);
- LOGGopher(sockfd, logline);
-
- break;
-
- case 1:
- /* it's a directory */
- listdir(sockfd, selstr);
-
- /* Log it */
- strcpy(logline, "retrieved directory ");
- strcat(logline, inputline);
- LOGGopher(sockfd, logline);
-
- break;
- }
- }
-
- return(0);
- }
-
- /*
- * Cache timeout value.
- * If cache is less than secs seconds old, it's ok.
- * Otherwise, compare time of cache to dir and all files in dir and dir/.cap.
- * If cache is newest, it's ok, otherwise it must be rebuilt.
- *
- * Not really great for big directories, but better in general for smaller
- * directories..
- */
-
- boolean
- Cachetimedout(cache, secs, dir)
- char *cache;
- int secs;
- char *dir;
- {
- STATSTR buf;
- int result;
- time_t now;
-
- result = rstat(cache, &buf);
-
- if (result != 0)
- return(-1);
-
- time(&now);
-
- if (DEBUG)
- printf("Cache now: %d, cache file: %d", now,buf.st_mtime);
-
- if ( now < (buf.st_mtime + secs))
- return(FALSE);
- else
- return(TRUE);
-
- }
-
- /*
- * Returns true (1) for a directory
- * false (0) for a file
- * -1 for anything else
- */
-
- boolean
- isadir(path)
- char *path;
- {
- STATSTR buf;
- int result;
-
- result = rstat(path, &buf);
-
- if (result != 0)
- return(-1);
-
- if (S_ISDIR(buf.st_mode)) {
- if (! access(path, F_OK))
- return(1);
- else
- return(-1);
- }
- else if (S_ISREG(buf.st_mode))
- return(0);
- else
- return(-1);
- }
-
-
- /*
- * This function tries to find out what type of file a pathname is.
- * It then fills in the VAR type variables ObjType & ServerPath with
- * corresponding info.
- */
- void
- Getfiletypes(newpath, filename, ObjType, ServerPath)
- char *newpath;
- char *filename;
- char *ObjType;
- char **ServerPath;
- {
- boolean dirresult;
- int Zefilefd;
- static char Zebuf[256];
- char *cp;
- static char Selstr[512];
-
-
- if (ServerPath != NULL) /* Don't overwrite existing path if any */
- *ServerPath = Selstr;
-
-
- dirresult = isadir(filename);
-
- if (dirresult == -1) { /** Symlink or Special **/
- *ObjType = '3';
- return;
- }
-
- if (dirresult == 1) {
- *ObjType = '1';
- *Selstr = '1';
- strcpy(Selstr +1, newpath);
- return;
- }
-
-
- else { /** Some kind of data file.... */
-
- /*** The default is a generic text file ***/
-
- *ObjType = '0';
- *Selstr = '0';
- strcpy(Selstr + 1, newpath);
-
- /*** Test and see if the thing exists... and is readable ***/
-
- if ((Zefilefd = ropen(filename, O_RDONLY)) < 0) {
- *ObjType = '3';
- return;
- }
-
- bzero(Zebuf, sizeof(Zebuf));
- read(Zefilefd, Zebuf, sizeof(Zebuf));
- close(Zefilefd);
-
- /*** Check the first few bytes for sound data ***/
-
- cp = Zebuf;
-
- if (strncmp(cp, ".snd", 4)==0) {
- *ObjType = 's';
- *Selstr = 's';
- strcpy(Selstr+1, newpath);
- }
-
- /*** Check and see if it's mailbox data ***/
-
- if (is_mail_from_line(Zebuf)==0) {
- *ObjType = '1';
- *Selstr = 'm';
- strcpy(Selstr+1, newpath);
- }
-
-
- /*** Check for uuencoding data ***/
-
- if (strncmp(cp,"begin",6) == 0) {
- *ObjType = '6';
- *Selstr = '6';
- strcpy(Selstr+1, newpath);
- }
-
- /*** Check for GIF magic code ***/
-
- if (strncmp(cp, "GIF", 3) == 0) {
- *ObjType = 'I';
- *Selstr = 'I';
- strcpy(Selstr + 1, newpath);
- }
-
- /*** Okay, now let's check for the stuff from gopherd.conf files ***/
- {
- char Gtype, *prefix;
-
- if (GDCExtension(Config, filename, &Gtype, &prefix)) {
- *ObjType = Gtype;
- strcpy(Selstr, prefix);
- strcpy(Selstr+strlen(prefix), newpath);
- }
- }
-
-
- }
-
- }
-
-
-
-
- /*
- ** This function lists out what is in a particular directory.
- ** it also outputs the contents of link files.
- **
- ** It also checks for the existance of a .cache file if caching is
- ** turned on...
- **
- ** Ack is this ugly.
- */
-
- void
- listdir(sockfd, pathname)
- int sockfd;
- char *pathname;
- {
- DIR *ZeDir;
- char sidename[256];
- char filename[256];
- static char newpath[512];
- #ifdef DL
- char dlpath[2]; /*** for DL**/
- char *dlout;
- #endif
- FILE *SideFile;
- static GopherStruct *Gopherp = NULL;
- char Typep, *Pathp, *cachefile;
- struct dirent *dp;
-
-
- /*** Make our gopherobj ****/
- if (Gopherp == NULL)
- Gopherp = GSnew();
-
- if (rchdir(pathname)<0) {
- Abortoutput(sockfd, "- Cannot access that directory");
- return;
- }
-
- if (UsingHTML)
- cachefile = ".cache.html";
- else
- cachefile = ".cache";
-
- if (Can_Browse(sockfd) == FALSE) {
- char tmpstr[256];
- Abortoutput(sockfd, GDCgetBummerMsg(Config));
- sprintf(tmpstr, "Denied access for %s", pathname);
- LOGGopher(sockfd, tmpstr);
- return;
- }
-
-
- if (Caching && Cachetimedout(cachefile, CACHE_TIME, ".")==FALSE) {
- /** Cache is still active, spit out the cache file
- and get outta here..... **/
- printfile(sockfd, cachefile, 0, -1);
- return;
- }
-
- /** If we didn't cache then we have to use a sorting directory... **/
- SortDir = GDnew(64);
-
- /* open "." since we just moved there - makes it work when not
- chroot()ing and using relative paths */
- if ((ZeDir = ropendir(".")) == NULL) {
- Abortoutput(sockfd, "Cannot get that directory");
- return;
- }
-
- for (dp = readdir(ZeDir); dp != NULL; dp = readdir(ZeDir)) {
-
- strcpy(newpath, pathname);
- if (newpath[strlen(newpath)-1] != '/')
- strcat(newpath, "/");
- strcat(newpath, dp->d_name);
-
- strcpy(sidename, "./.cap/");
- strcpy(filename, dp->d_name);
- strcat(sidename, dp->d_name);
-
- if (filename[0] == '.' &&
- isadir(filename)==0 &&
- strncmp(filename, ".cache", 6) !=0) {
- /*** This is a link file, let's process it ***/
- int linkfd;
-
- linkfd = uopen(filename, O_RDONLY);
-
- if (linkfd >0) {
- GDfromLink(SortDir, linkfd, Zehostname, GopherPort);
- close(linkfd);
- }
-
- }
-
- /** Only chew list out files that don't start with a dot **/
- /** or aren't named dev, usr, bin, etc, or core. **/
-
- if ((filename[0] != '.') && !GDCignore(Config, filename)) {
-
- /** Check to see if there's a set-aside file with more info ***/
- /** But first initialize the Gopherstruct **/
-
- GSinit(Gopherp);
-
- GSsetHost(Gopherp, Zehostname);
- GSsetPort(Gopherp, GopherPort);
- Typep = '\0';
- Pathp = NULL;
-
-
- Getfiletypes(newpath, filename, &Typep, &Pathp);
-
- if (Typep =='3')
- continue;
-
- GSsetType(Gopherp, Typep);
- GSsetPath(Gopherp, Pathp);
-
-
- if (GSgetTitle(Gopherp) == NULL) {
- /*** Check to see if we have a compressed file ***/
-
- if (strcmp(filename + strlen(filename) -2, ".Z") ==0 &&
- strcmp(filename + strlen(filename) -6, ".tar.Z") != 0)
- filename[strlen(filename) - 2] = '\0';
-
- GSsetTitle(Gopherp, filename);
- }
- else
- GSsetTitle(Gopherp, filename);
-
-
- if ((SideFile = rfopen(sidename, "r"))!=0) {
- if (DEBUG == TRUE)
- printf("Side file name: %s\n", sidename);
- Process_Side(SideFile, Gopherp);
- }
-
- #ifdef DL
- /* Process a "dl" description if there is one! */
-
- dlpath[0] = '.';
- dlpath[1] = '\0';
- dlout = getdesc(NULL,dlpath,filename,0);
-
- if (DEBUG)
- printf("dl: %s %s %s\n", dlpath, filename, dlout);
- if (dlout != NULL) {
- GSsetTitle(Gopherp, dlout);
- }
- #endif
-
- /*** Add the entry to the directory ***/
-
- GDaddGS(SortDir, Gopherp);
-
- }
- }
-
- GDsort(SortDir);
-
- if (UsingHTML) {
- int aboutfd;
-
- aboutfd = uopen(".about.html", O_RDONLY);
- if (aboutfd > 0) {
- while (readline(aboutfd, newpath, 512))
- writestring(sockfd, newpath);
- close(aboutfd);
- }
-
- GDtoNetHTML(SortDir, sockfd);
- }
- else {
- GDtoNet(SortDir, sockfd);
- writestring(sockfd, ".\r\n");
- }
-
- /*
- * Write out the cache... *After* we send out the data to the net.
- */
- if (Caching) {
- int cachefd;
-
- cachefd = uopen(cachefile, O_WRONLY|O_CREAT|O_TRUNC, 0755);
-
- if (cachefd != 0) {
- if (DEBUG) {
- printf("Caching directory...\n");
- }
- if (UsingHTML) {
- int aboutfd;
-
- aboutfd = uopen(".about.html", O_RDONLY);
- if (aboutfd > 0) {
- while (readline(aboutfd, newpath, 512))
- writestring(cachefd, newpath);
- close(aboutfd);
- }
-
- GDtoNetHTML(SortDir, cachefd);
- }
- else
- GDtoNet(SortDir, cachefd);
-
- close(cachefd);
- }
- }
-
- closedir(ZeDir);
- }
-
-
- /*
- * This processes a file containing any subset of
- * Type, Name, Path, Port or Host, and returns pointers to the
- * overriding data that it finds.
- *
- * The caller may choose to initialise the pointers - so we don't
- * touch them unless we find an over-ride.
- */
-
- void
- Process_Side(sidefile, Gopherp)
- FILE *sidefile;
- GopherObj *Gopherp;
- {
- char inputline[MAXLINE];
- char *cp;
-
-
- inputline[0] = '\0';
-
- for (;;) {
- for (;;) {
- cp = fgets(inputline, 1024, sidefile);
- if (inputline[0] != '#' || cp == NULL)
- break;
- }
-
- /*** Test for EOF ***/
- if (cp==NULL)
- break;
-
- ZapCRLF(inputline); /* should zap tabs as well! */
-
- /*** Test for the various field values. **/
-
- if (strncmp(inputline, "Type=", 5)==0) {
- GSsetType(Gopherp, inputline[5]);
- if (inputline[5] == '7') {
- /*** Might as well set the path too... ***/
- *(GSgetPath(Gopherp)) = '7';
- }
- if (inputline[5] == '9') {
- /*** Might as well set the path too... ***/
- *(GSgetPath(Gopherp)) = '9';
- }
- }
-
- else if (strncmp(inputline, "Name=", 5)==0) {
- GSsetTitle(Gopherp, inputline+5);
- }
-
- else if (strncmp(inputline, "Host=", 5)==0) {
- GSsetHost(Gopherp, inputline+5);
- }
-
- else if (strncmp(inputline, "Port=", 5)==0) {
- GSsetPort(Gopherp, atoi(inputline+5));
- }
-
- else if (strncmp(inputline, "Path=", 5)==0) {
- GSsetPath(Gopherp, inputline+5);
- }
-
- else if (strncmp(inputline, "Numb=", 5)==0) {
- GSsetNum(Gopherp, atoi(inputline+5));
- }
-
- else if (strncmp(inputline, "Name=", 5)==0) {
- GSsetTitle(Gopherp, inputline+5);
- }
-
- }
-
- fclose(sidefile);
- }
-
-
-
-
-
- /*
- ** This function opens the specified file, starts a zcat if needed,
- ** and barfs the file across the socket.
- **
- ** It now also checks and sees if access is allowed
- **
- **
- */
-
- void
- printfile(sockfd, pathname, startbyte, endbyte)
- int sockfd;
- char *pathname;
- int startbyte, endbyte;
- {
- FILE *ZeFile;
- char inputline[512];
-
-
- /*** Check and see if the peer has permissions to read files ***/
-
- if (Can_Read(sockfd) == FALSE) {
- char tmpstr[256];
- if (writestring(sockfd, GDCgetBummerMsg(Config)) <0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
- writestring(sockfd, "\r\nBummer.....\r\n.\r\n");
- sprintf(tmpstr, "Denied access for %s", pathname);
- LOGGopher(sockfd, tmpstr);
- return;
- }
-
- if (UsingHTML && strcmp(pathname, ".cache.html") != 0) {
- writestring(sockfd, "<XMP>\r\n");
- }
-
-
- if ( (ZeFile = rfopen(pathname, "r")) == NULL) {
- /*
- * The specified file does not exist
- */
- char notexistline[256];
- sprintf(notexistline, "'%s' does not exist!!", pathname);
- Abortoutput(sockfd, notexistline);
-
- return;
- }
-
- if (startbyte != 0)
- fseek(ZeFile, startbyte, 0);
-
- {
- FILE *pp;
- if (pp = specialfile(ZeFile, pathname)) {
- fclose(ZeFile);
- ZeFile = pp;
- }
- }
-
-
- while (fgets(inputline, MAXLINE, ZeFile) != NULL) {
-
- ZapCRLF(inputline);
-
- /** Period on a line by itself, double it.. **/
- if (*inputline == '.' && inputline[1] == '\0') {
- inputline[1] = '.';
- inputline[2] = '\0';
- }
-
- strcat(inputline, "\r\n");
- if (writestring(sockfd, inputline) <0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
-
- if (endbyte >0) {
- if (ftell(ZeFile) >= endbyte)
- break;
- }
- }
-
- Specialclose(ZeFile);
-
- if (UsingHTML) {
- writestring(sockfd, "</XMP>\r\n");
- }
-
- if (writestring(sockfd, ".\r\n")<0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
- }
-
-
- #define BUFSIZE 1523 /* A pretty good value for ethernet */
-
- void
- echosound(sockfd, filename)
- int sockfd;
- char *filename;
- {
-
- FILE *sndfile;
- unsigned char in[BUFSIZE];
- register int j;
- int gotbytes;
-
- if (Can_Read(sockfd) == FALSE) {
- char tmpstr[256];
- if (writestring(sockfd, GDCgetBummerMsg(Config)) <0)
- LOGGopher(sockfd, "Client went away"), exit(-1);
- writestring(sockfd, "\r\nBummer.....\r\n.\r\n");
- sprintf(tmpstr, "Denied access for %s", filename);
- LOGGopher(sockfd, tmpstr);
- return;
- }
-
- if (strcmp(filename, "-") == 0) {
- /*** Do some live digitization!! **/
- sndfile = popen("record -", "r");
- }
- else
- sndfile = rfopen(filename, "r");
-
- while(1) {
- gotbytes = fread(in, 1, BUFSIZE, sndfile);
-
- if (gotbytes == 0)
- break; /*** end of file or error... ***/
-
- j = writen(sockfd, in, gotbytes);
-
- if (j == 0)
- break; /*** yep another error condition ***/
-
- }
- }
-
-